package com.googlecode.allinclusive.fw.database.ibatis.impl;

import java.lang.reflect.Array;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.googlecode.allinclusive.fw.database.ibatis.EntityManager;
import com.googlecode.allinclusive.fw.database.ibatis.IllegalClassTypeException;
import com.googlecode.allinclusive.fw.database.ibatis.SQLHolder;
import com.ibatis.sqlmap.client.SqlMapExecutor;

/*
 * <bean id="entityManager" class="com.googlecode.allinclusive.fw.database.ibatis.impl.EntityManageriBatisImpl">
 * 		<property name="dataSource" ref="dataGuardDs"/>
 * 		<property name="sqlMapClient" ref="sqlMapClient"/>
 * </bean>
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class EntityManageriBatisImpl extends SqlMapClientDaoSupport implements EntityManager {

	/** log instance*/
    private static Log log = LogFactory.getLog(EntityManageriBatisImpl.class);

	/**
	 * 执行SQL,返回单条指定类型的对象
	 * @param sqlID SQL-ID
	 * @param bindParams SQL参数
	 * @param clazz 返回类型
	 * @return SQL执行结果
	 */
    @Override
    public <E> E executeForObject(String sqlID,
                                   Object bindParams,
                                   Class clazz) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObject Start.");
        }

        // SqlMapClientTemplate
        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        // 执行SQL
        Object obj = sqlMapTemp.queryForObject(sqlID, bindParams);
        if (log.isDebugEnabled() && obj != null) {
            log.debug("Return type:" + obj.getClass().getName());
        }

        E rObj = null;
        try {
            if (clazz != null && obj != null) {
                rObj = (E) clazz.cast(obj);
            }
        } catch (ClassCastException e) {
            log.error(IllegalClassTypeException.ERROR_ILLEGAL_CLASS_TYPE);
            throw new IllegalClassTypeException(e);
        }

        if (log.isDebugEnabled()) {
            log.debug("executeForObject End.");
        }

        return rObj;
    }

    /**
     * 执行SQL,返回多条指定类型的对象数组
     * @param sqlID SQL-ID
     * @param bindParams SQL参数
     * @param clazz 返回类型
     * @return SQL执行结果
     */
    @Override
    public <E> E[] executeForObjectArray(String sqlID, Object bindParams,
            Class clazz) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectArray Start.");
        }

        if (clazz == null) {
            log.error(IllegalClassTypeException.ERROR_ILLEGAL_CLASS_TYPE);
            throw new IllegalClassTypeException();
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();
        // 执行SQL 
        List<E> list = sqlMapTemp.queryForList(sqlID, bindParams);

        E[] retArray = (E[]) Array.newInstance(clazz, list.size());
        try {
            list.toArray(retArray);
        } catch (ArrayStoreException e) {
            log.error(IllegalClassTypeException.ERROR_ILLEGAL_CLASS_TYPE);
            throw new IllegalClassTypeException(e);
        }

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectArray End.");
        }

        return retArray;
    }

    /**
     * 执行SQL,返回多条指定类型的对象数组
     * @param sqlID SQL-ID
     * @param bindParams SQL参数
     * @param clazz 返回类型
     * @param beginIndex 开始索引
     * @param maxCount 最大件数
     * @return SQL执行结果
     */
    @Override
    public <E> E[] executeForObjectArray(String sqlID, Object bindParams,
            Class clazz, int beginIndex, int maxCount) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectArray Start.");
        }

        if (clazz == null) {
            log.error(IllegalClassTypeException.ERROR_ILLEGAL_CLASS_TYPE);
            throw new IllegalClassTypeException();
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        List<E> list = sqlMapTemp.queryForList(sqlID, bindParams, beginIndex,
                maxCount);

        E[] retArray = (E[]) Array.newInstance(clazz, list.size());
        try {
            list.toArray(retArray);
        } catch (ArrayStoreException e) {
            log.error(IllegalClassTypeException.ERROR_ILLEGAL_CLASS_TYPE);
            throw new IllegalClassTypeException(e);
        }

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectArray End.");
        }

        return retArray;
    }

    /**
     * 执行SQL,返回多条指定类型的对象List
     * @param sqlID SQL-ID
     * @param bindParams SQL参数
     * @return SQL执行结果
     */
    @Override
    public <E> List<E> executeForObjectList(String sqlID, Object bindParams) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectList Start.");
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        List<E> list = sqlMapTemp.queryForList(sqlID, bindParams);
        
        if (log.isDebugEnabled()) {
            log.debug("executeForObjectList End.");
        }

        return list;
    }

    /**
     * 执行SQL,返回多条指定类型的对象List
     * @param sqlID SQL-ID
     * @param bindParams SQL参数
     * @param beginIndex 开始索引
     * @param maxCount 最大件数
     * @return SQL执行结果
     */
    @Override
    public <E> List<E> executeForObjectList(String sqlID, Object bindParams,
            int beginIndex, int maxCount) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObjectList Start.");
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        List<E> list = sqlMapTemp.queryForList(sqlID, bindParams, beginIndex,
                maxCount);
        
        if (log.isDebugEnabled()) {
            log.debug("executeForObjectList End.");
        }

        return list;
    }    
    
	/**
	 * 执行更新SQL
	 * @param sqlID SQL-ID
	 * @param bindParams SQL参数
	 * @return 更新记录数
	 */
    @Override
    public int executeUpdate(String sqlID, Object bindParams) {

        if (log.isDebugEnabled()) {
            log.debug("execute Start.");
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        int row = sqlMapTemp.update(sqlID, bindParams);

        if (log.isDebugEnabled()) {
            log.debug("execute End. success count:" + row);
        }
        return row;
    }

    /**
     * 批处理方式执行更新SQL
     * @param sqlHolders
     * @return　更新记录数
     */
	@Override
    public int executeBatch(final List<SQLHolder> sqlHolders) {

        Integer result = 0;
        result = (Integer) getSqlMapClientTemplate().execute(
                new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor)
                  throws SQLException {
                StringBuilder logStr = new StringBuilder();
                if (log.isDebugEnabled()) {
                    log.debug("Batch SQL count:" + sqlHolders.size());
                }
                executor.startBatch();
                for (SQLHolder sqlHolder : sqlHolders) {
                    executor.update(
                        sqlHolder.getSqlID(), sqlHolder.getBindParams());
                    
                    if (log.isDebugEnabled()) {
                        logStr.setLength(0);
                        logStr.append("Call update sql. - SQL_ID:'");
                        logStr.append(sqlHolder.getSqlID());
                        logStr.append("' Parameters:");
                        logStr.append(sqlHolder.getBindParams());
                        log.debug(logStr.toString());
                    }
                }
                return executor.executeBatch();
            }
        });
        
        if (log.isDebugEnabled()) {
            log.debug("ExecuteBatch complete. Result:" + result);
        }
        return result.intValue();
    }
    
	/**
	 * 调用存储过程
	 * @param sqlID  SQL-ID
	 * @param bindParams SQL参数
	 */
    @Override
    public void callProcedure(String sqlID, Object bindParams) {

        if (log.isDebugEnabled()) {
            log.debug("executeForObject Start.");
        }

        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();
        // 执行SQL
        sqlMapTemp.queryForObject(sqlID, bindParams);

        if (log.isDebugEnabled()) {
            log.debug("executeForObject End.");
        }
    }
}
